// 该文件是 Excalidraw 的核心代码，负责处理画布的绘制、鼠标事件、键盘事件等。
class Toolbar {
  name = 'Selector' // 默认工具栏选择器
  toolbars = {
    'toolbar-selection': 'Selector',
    'toolbar-rectangle': 'Rectangle',
    'toolbar-diamond': 'Diamond',
    'toolbar-ellipse': 'Circle',
    'toolbar-arrow': 'ArrowLine',
    'toolbar-bezier': 'BezierLine',
    'toolbar-line': 'Line',
    'toolbar-text': 'Textbox',
    'toolbar-freedraw': 'Brush',
  }
  constructor() {
    this.cvsinit()
    this.init()
    this.listener()
  }
  cvsinit() {
    this.cvs = document.getElementById('myCanvas')
    this.ctx = this.cvs.getContext('2d')
    this.dpr = devicePixelRatio || 1
  }
  canvasInit() {
    const w = window.outerWidth
    const h = window.outerHeight
    this.cvs.width = w * dpr
    this.cvs.height = h * dpr
    this.cvs.style.setProperty('width', w + 'px')
    this.cvs.style.setProperty('height', h + 'px')
  }
  init() {
    this.root = document.querySelector('.App-toolbar')
    this.panel = document.querySelector('.panelColumn')
    this.inputs = Array.from(this.root.querySelectorAll('input[name=editor-current-shape]'))
    this.colorPickerList = this.panel.querySelectorAll('.color-picker__top-picks')
    this.buttonList = this.panel.querySelectorAll('.buttonList')
    this.arrowList = this.panel.querySelector('.iconSelectList')
  }

  listener() {
    this.root.addEventListener('click', this.toolbarHandler.bind(this))

    this.colorPickerList.forEach(picker => {
      picker.addEventListener('click', this.colorPickerHandler.bind(this))
    })

    this.buttonList.forEach(btn => {
      btn.addEventListener('click', this.buttonListHandler.bind(this))
    })

    this.arrowList.addEventListener('click', this.arrowClickHandler.bind(this))
  }

  toolbarHandler(e) {
    const { target: { tagName, dataset } } = e
    if (tagName !== 'INPUT') return
    this.name = this.toolbars[dataset.testid]
    this.showTextboxPanel()
    this.showLinePointPanel()
  }

  showTextboxPanel() {
    const isTextbox = (el) => this.name === 'Textbox' ? el.classList.remove('hidden') : el.classList.add('hidden')
    const items = this.panel.querySelectorAll('.textbox-fieldset')
    items.forEach(isTextbox)
  }

  showLinePointPanel() {
    const root = this.panel.querySelector('fieldset.line-point')
    this.name.includes('Line') ? root.classList.remove('hide') : root.classList.add('hide')
  }

  colorPickerHandler(e) {
    const { target } = e
    if (target.tagName !== 'BUTTON') return
    target.classList.add('active')
    target.parentNode.querySelectorAll('button').forEach(btn => {
      (btn !== target) && btn.classList.remove('active')
    })
    this.setLastButtonColor(target)
  }

  setLastButtonColor(target) {
    // 选中最后一个按钮，设置其颜色
    const node = target.parentNode.parentNode
    const last = node.lastElementChild
    if (target.classList.contains('is-transparent')) {
      last.classList.add('is-transparent')
    } else {
      last.classList.remove('is-transparent')
      last.style.setProperty('--swatch-color', target.style.getPropertyValue('--swatch-color'))
    }
  }

  buttonListHandler(e) {
    const { target } = e
    target.classList.add('active')
    target.parentNode.querySelectorAll('button').forEach(btn => {
      (btn !== target) && btn.classList.remove('active')
    })
  }

  arrowClickHandler(e) {
    const { target } = e
    if (target.tagName === 'BUTTON') {
      this.target = target
      const root = target.parentNode
      const popover = root.parentNode.querySelector('.popover')
      root.appendChild(popover)
      popover.addEventListener('mouseleave', this.arrowMouseleaveHandler.bind(this))
    }
  }
  arrowMouseleaveHandler(e) {
    const root = this.target.parentNode
    const popover = root.parentNode.querySelector('.popover')
    const last = root.parentNode.lastElementChild
    last.appendChild(popover)
  }

  hasShortcutKey(key) {
    const map = ['h', 'v', '1', 'r', '2', 'd', '3', 'o', '4', 'a', '5', 'c', 'l', '6', 'p', '7', 't', '8']
    return map.includes(key)
  }
  keyshortcuts(key) {
    const el = this.inputs.find(inp => {
      return inp.ariaKeyShortcuts.includes(String(key).toLocaleUpperCase())
    })
    return el && el.parentNode.click()
  }
}
const toolbar = new Toolbar()
const shape = new Shape()
const canvasHandler = new CanvasHandler(shape)

const cvs = toolbar.cvs
const ctx = toolbar.ctx
const dpr = toolbar.dpr

toolbar.canvasInit()

shape.draw(ctx, function () {
  ctx.clearRect(0, 0, cvs.width, cvs.height)
})

// canvas 鼠标按下事件
cvs.addEventListener('mousedown', canvasHandler.mousedown.bind(canvasHandler))
// canvas 鼠标离开画布时,清除鼠标事件监听
cvs.addEventListener('mouseleave', canvasHandler.mouseleave.bind(canvasHandler))
// canvas 双击事件
cvs.addEventListener('dblclick', canvasHandler.dblclick.bind(canvasHandler))

// 监听键盘事件
document.addEventListener('keydown', keydownHandle)
// addEventListener keycode
const keyActions = {
  'ctrl+]': () => shape.up(),
  'ctrl+[': () => shape.down(),
  'ctrl+shift+{': () => shape.moveBottom(),
  'ctrl+shift+}': () => shape.moveTop(),
  'Backspace': () => shape.remove(),
  'Delete': () => shape.remove(),
  'cmd+Enter': textboxUpdate,
  'Escape': textboxUpdate,
  'ArrowUp': () => shape.move('up', -1),
  'shift+ArrowUp': () => shape.move('up', -10),
  'ArrowDown': () => shape.move('down', 1),
  'shift+ArrowDown': () => shape.move('down', 10),
  'ArrowLeft': () => shape.move('left', -1),
  'shift+ArrowLeft': () => shape.move('left', -10),
  'ArrowRight': () => shape.move('right', 1),
  'shift+ArrowRight': () => shape.move('right', 10),
}
function hasAction(key) {
  return keyActions.hasOwnProperty(key)
}
function keydownHandle(event) {
  //
  // 检查按下的键是否为指定的键:
  const actionKey = getGroupKey(event)
  console.log("%c [GROUP KEY]: ", "color:#7f2b82", actionKey)

  if (hasAction(actionKey)) {
    if (!shape.empty()) shape.setRefresh(true)
    keyActions[actionKey]()
  }

  if (!shape.getActive()?.isTextbox && toolbar.hasShortcutKey(actionKey)) {
    toolbar.keyshortcuts(actionKey)
  }
}

function getGroupKey(event) {
  const { metaKey, ctrlKey, shiftKey, altKey, key } = event
  let actionKey = '';
  (ctrlKey) && (actionKey += 'ctrl+');
  (shiftKey) && (actionKey += 'shift+');
  (altKey) && (actionKey += 'alt+');
  (metaKey) && (actionKey += 'cmd+');
  (key) && (actionKey += key)
  return actionKey
}

function textboxUpdate() {
  const textarea = document.getElementById('textbox')
  if (!textarea) return
  textarea.dispatchEvent(new Event('blur'))
}
